package com.echo.im.client.status;

import com.echo.im.client.constant.Constant;
import com.echo.im.client.status.cache.CacheService;
import com.echo.im.client.status.data.DataService;
import org.springframework.stereotype.Repository;

import java.util.*;

/**
 *
 * 使用特殊标记值来表示Redis中没有数据，简化逻辑。
 * 其实这里有个逻辑很细，如何说明redis没有数据，我们就用一个空map来标记
 * 如果redis没有数据，本地缓存就存空map，如果本地缓存不知道redis有没有数据，就存null
 * 所以就等于本地的缓存是一个 只要是map就是确定值，就是我们本地就有答案，如果是null，本地就没有答案，必须去redis寻找答案
 *
 * @author echo
 */
public class UserStatusRepository {

    /**
     *  特殊标记值，标记 redis 没有数据，用户没有上线
     */

    private final CacheService cacheService;
    private final DataService dataService;

    public UserStatusRepository(CacheService cacheService, DataService dataService) {
        this.cacheService = cacheService;
        this.dataService = dataService;
    }

    /**
     * 不可能返回null，返回空map或者有值的map
     * @param userId
     * @return
     */
    public Map<Integer, Integer> findTerminalServerIdMap(Long userId) {
        Object cachedValue = cacheService.getCacheData(userId);
        //如果为null，证明本地没有数据，从数据库中获取
        if (cachedValue == null) {
            Map<Integer, Integer> terminalStatus = dataService.fetchTerminalServerIdMap(userId);
            cacheService.updateCache(userId, terminalStatus);
            return terminalStatus;
        }else {
            // 如果不为null，证明本地有数据，直接返回
            return (Map<Integer, Integer>) cachedValue;
        }
    }

    /**
     * 不可能返回null，返回空map或者有值的map
     * @param userIds
     * @return
     */
    public Map<Long, Map<Integer, Integer>> findUserTerminalServerIdMap(List<Long> userIds) {
        Map<Long, Map<Integer, Integer>> result = new HashMap<>();
        List<Long> missingUserIds = new ArrayList<>();

        for (Long userId : userIds) {
            Object cachedValue = cacheService.getCacheData(userId);
            if (cachedValue == null) {
                missingUserIds.add(userId);
                continue;
            }
            if (cachedValue == Constant.NULL_MARKER){
                continue;
            }
            result.put(userId, (Map<Integer, Integer>) cachedValue);
        }

        if (!missingUserIds.isEmpty()) {
            for (Long userId : missingUserIds) {
                Map<Integer, Integer> terminalStatus = dataService.fetchTerminalServerIdMap(userId);
                cacheService.updateCache(userId, terminalStatus);
                result.put(userId, terminalStatus);
            }
        }

        return result;
    }
}
